Add a function to request motion events
authorMatthias Clasen <mclasen@redhat.com>
Fri, 21 Feb 2020 21:38:36 +0000 (16:38 -0500)
committerMatthias Clasen <mclasen@redhat.com>
Thu, 27 Aug 2020 17:33:45 +0000 (13:33 -0400)
We want to ensure that the pointer position is reflected
when widget geometry changes, so add a function that tells
GDK "please create a motion event at the current position
on this surface, if one doesn't happen already".

gdk/gdksurface.c
gdk/gdksurfaceprivate.h

index f89061a002be0cd49840bec9ed04b683fb561383..3a03292251c3f0ecb2fadf422b5714821f6a3ee4 100644 (file)
@@ -2338,6 +2338,43 @@ gdk_drag_begin (GdkSurface          *surface,
   return GDK_SURFACE_GET_CLASS (surface)->drag_begin (surface, device, content, actions, dx, dy);
 }
 
+static void
+gdk_surface_ensure_motion (GdkSurface *surface)
+{
+  GdkDisplay *display;
+  GdkSeat *seat;
+  GdkDevice *device;
+  GdkEvent *event;
+  double x, y;
+  GdkModifierType state;
+
+  if (!surface->request_motion)
+    return;
+
+  surface->request_motion = FALSE;
+
+  display = gdk_surface_get_display (surface);
+  seat = gdk_display_get_default_seat (display);
+  if (!seat)
+    return;
+
+  device = gdk_seat_get_pointer (seat);
+
+  if (!gdk_surface_get_device_position (surface, device, &x, &y, &state))
+    return;
+
+  event = gdk_motion_event_new (surface,
+                                device,
+                                NULL,
+                                GDK_CURRENT_TIME,
+                                state,
+                                x, y,
+                                NULL);
+
+  gdk_surface_handle_event (event);
+  gdk_event_unref (event);
+}
+
 static void
 gdk_surface_flush_events (GdkFrameClock *clock,
                           void          *data)
@@ -2345,6 +2382,7 @@ gdk_surface_flush_events (GdkFrameClock *clock,
   GdkSurface *surface = GDK_SURFACE (data);
 
   _gdk_event_queue_flush (surface->display);
+  gdk_surface_ensure_motion (surface);
   _gdk_display_pause_events (surface->display);
 
   gdk_frame_clock_request_phase (clock, GDK_FRAME_CLOCK_PHASE_RESUME_EVENTS);
@@ -2806,7 +2844,12 @@ gdk_surface_handle_event (GdkEvent *event)
     }
   else
     {
-      g_signal_emit (gdk_event_get_surface (event), signals[EVENT], 0, event, &handled);
+      GdkSurface *surface = gdk_event_get_surface (event);
+
+      if (gdk_event_get_event_type (event) == GDK_MOTION_NOTIFY)
+        surface->request_motion = FALSE;
+
+      g_signal_emit (surface, signals[EVENT], 0, event, &handled);
     }
 
   if (GDK_PROFILER_IS_RUNNING)
@@ -2815,6 +2858,27 @@ gdk_surface_handle_event (GdkEvent *event)
   return handled;
 }
 
+/*
+ * gdk_surface_request_motion:
+ * @surface: a #GdkSurface
+ *
+ * Request that the next frame cycle should deliver a motion
+ * event for @surface if the pointer is over it, regardless
+ * whether the pointer has moved or not. This is used by GTK
+ * after moving widgets around.
+ */
+void
+gdk_surface_request_motion (GdkSurface *surface)
+{
+  GdkFrameClock *frame_clock;
+
+  surface->request_motion = TRUE;
+
+  frame_clock = gdk_surface_get_frame_clock (surface);
+  if (frame_clock)
+    gdk_frame_clock_request_phase (frame_clock, GDK_FRAME_CLOCK_PHASE_FLUSH_EVENTS);
+}
+
 /**
  * gdk_surface_translate_coordinates:
  * @from: the origin surface
index 50c39d5cc18d1943f4e988f01c1d81eb1462edf6..f84f996f706482f151f6a0aa91b0d9b8a502fd9d 100644 (file)
@@ -72,6 +72,7 @@ struct _GdkSurface
   guint frame_clock_events_paused : 1;
   guint autohide : 1;
   guint shortcuts_inhibited : 1;
+  guint request_motion : 1;
 
   struct {
     GdkGravity surface_anchor;
@@ -327,6 +328,9 @@ void       gdk_surface_constrain_size      (GdkGeometry    *geometry,
                                             int            *new_width,
                                             int            *new_height);
 
+GDK_AVAILABLE_IN_ALL
+void           gdk_surface_request_motion (GdkSurface *surface);
+
 G_END_DECLS
 
 #endif /* __GDK_SURFACE_PRIVATE_H__ */